package cn.com.cifi.mars.web;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import javax.annotation.PreDestroy;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.oltu.oauth2.client.OAuthClient;
import org.apache.oltu.oauth2.client.URLConnectionClient;
import org.apache.oltu.oauth2.client.request.OAuthClientRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import cn.com.cifi.mars.common.redis.RedisTemplateUtil;
import cn.com.cifi.mars.config.jwt.PassToken;
import cn.com.cifi.mars.entity.common.IdmUser;
import cn.com.cifi.mars.service.IdmUserService;
import cn.com.cifi.mars.util.JwtUtil;
import cn.com.cifi.mars.util.json.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONObject;

@Slf4j
@Controller
public class IndexController {

    @Autowired
    private RedisTemplateUtil redisTemplateUtil;

    @Autowired
    private IdmUserService idmUserService;

    @Value("${gitlabServerUrl}")
    private String gitlabServerUrl;
    
    @Value("${authorizePath}")
    private String authorizePath ;
    
    @Value("${clientId}")
    private String clientId ;
    
    @Value("${app_url}")
    private String app_url ;
    
    @Value("${profileUrl}")
    private String profileUrl;
    
    @Value("${clientSecret}")
    private String clientSecret;
  
    @Value("${tokenPath}")
    private String tokenPath;
    
    @RequestMapping(value = "/", method = {RequestMethod.GET})
    public String home() {
        return "redirect:/swagger-ui.html";
    }

    OAuthClient oAuthClient = new OAuthClient(new URLConnectionClient());

    @PreDestroy
    public void cleanUp() {
        oAuthClient.shutdown();
    }

    @PassToken
    @RequestMapping(value = "/login", method = {RequestMethod.GET})
    public void index(HttpServletRequest req, HttpServletResponse response) throws Throwable {

        String callbackUrl = app_url+"/api/sso";

        String	sourceUrl = req.getParameter("from");
        log.info("sourceUrl login --> " + sourceUrl);
        
        if (null != sourceUrl) {
            sourceUrl = URLEncoder.encode(sourceUrl);
        }
        
        OAuthClientRequest request = OAuthClientRequest.authorizationLocation(gitlabServerUrl + authorizePath).setState(sourceUrl)
                .setClientId(clientId).setRedirectURI(callbackUrl).setResponseType("code").buildQueryMessage();
        
        response.sendRedirect(request.getLocationUri());
    }
    
    @PassToken
    @RequestMapping(value = "/api/sso", method = {RequestMethod.GET})
    public @ResponseBody
    String doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String code = request.getParameter("code");
        String sourceUrl =request.getParameter("state");
        	sourceUrl = (StringUtils.isEmpty(sourceUrl)?null:URLDecoder.decode(sourceUrl)) ;
        log.info("sourceUrl sso -------------------> " + sourceUrl);
        String callbackUrl = app_url+"/api/sso";
        String access_token = null;
        String uid = null;
        String sessionToken;

        // 获取accessToken
        if (code != null && !"".equals(code)) {
            String params = "client_id=CLIENT_ID&client_secret=CLIENT_SECRET&grant_type=authorization_code&redirect_uri=REDIRECTURL&code=CODE";
            String replacedParams = params.replace("CLIENT_ID", clientId).replace("CLIENT_SECRET", clientSecret)
                    .replace("REDIRECTURL", callbackUrl).replace("CODE", code);

        	log.info("### accessTokenByJson-reqUrl:"+gitlabServerUrl + tokenPath);
        	log.info("### accessTokenByJson-reqParam:"+ replacedParams);
        	
            String access_token_str = sendPost(gitlabServerUrl + tokenPath, replacedParams);

            log.info("### accessTokenByJson-resp:"+access_token_str);
            
            // AccessToken
            Map tokenMap = JsonUtils.convertJsonToMap(access_token_str);
            access_token = (String) tokenMap.get("access_token");
        }

        // 获取用户信息
        if (null != access_token) {
        	log.info("### profileByJson-reqUrl:"+gitlabServerUrl+"====="+ profileUrl);
        	log.info("### profileByJson-reqParam:"+ access_token);
        	
            String principal_json = sendPost(gitlabServerUrl + profileUrl, access_token);

            // 用户信息
            JSONObject pfjsonObj = JSONObject.fromObject(principal_json);
            
            log.info("### profileByJson-resp:"+pfjsonObj.toString());
            
            if ("true".equals(pfjsonObj.get("status").toString())) {
                if (pfjsonObj.has("id")) {
                    log.info("auth user by mdm success, user id is {}", pfjsonObj.get("id"));
                }
                if (pfjsonObj.has("attributes")) {
                    JSONObject attrObj = JSONObject.fromObject(pfjsonObj.get("attributes"));
                    if (attrObj.has("uid")) {
                        uid = (String) attrObj.get("uid");
                    }
                }
            } else {
                response.sendRedirect(app_url+"/#/login?msg=user_status_exception");
            }

            IdmUser user = idmUserService.selectByUserName(uid);

            if (user == null) {
                response.sendRedirect(app_url+"/#/login?msg=errorId_" + uid +"-user_not_found");
            }

            // 生成token
            sessionToken = JwtUtil.createToken(uid);

            log.info("sessionToken ---> " + sessionToken);

            redisTemplateUtil.set("mars_user_" + sessionToken, user, 8, TimeUnit.HOURS);
            log.info("-> {}", redisTemplateUtil.get("mars_user_" + sessionToken));
            if(sourceUrl!=null) {
            	String url= sourceUrl.split("hash")[0]+"#/getToken?token="+sessionToken+"&from="+URLEncoder.encode(sourceUrl.replace("hash","#"));
                response.sendRedirect(url);
            }
        } else {
        	log.info("app_url-------------------> " + app_url);
            response.sendRedirect(app_url+"/#/login?msg=");
        }

        return null;
    }
    /**
     * 健康监测
     * @return
     * @throws Throwable
     */
    @RequestMapping(value = "/healthCheck", method = {RequestMethod.GET})
    public String healthCheck(HttpServletRequest req, HttpServletResponse response) throws Throwable {
    	return null;
    }
    
 
    private String sendPost(String url, String param) {
        PrintWriter out = null;
        BufferedReader in = null;
        String result = "";
        try {
            URL realUrl = new URL(url);
            // 打开和URL之间的连接
            URLConnection conn = realUrl.openConnection();
            // 发送POST请求必须设置如下两行
            conn.setDoOutput(true);
            conn.setDoInput(true);
            // 获取URLConnection对象对应的输出流
            out = new PrintWriter(conn.getOutputStream());
            // 发送请求参数
            out.print(param);
            // flush输出流的缓冲
            out.flush();
            // 定义BufferedReader输入流来读取URL的响应
            in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            String line;
            while ((line = in.readLine()) != null) {
                result += line;
            }
        } catch (Exception e) {
            log.error("###### errorMsg: ", e);
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException ex) {
                log.error("###### errorMsg: ", ex);
            }
        }
        return result;
    }


}
